<template>
  <div class="editor" :class="fullCss">
    <div ref="conRef"></div>
  </div>
</template>
<script lang="ts" setup>
import {ref, onMounted, computed, watch, nextTick, onBeforeUnmount} from 'vue'
import E from 'wangeditor'
import {useFormItem} from 'element-plus'
import {FullScreenMenu} from './custom-menus'

const {formItem} = useFormItem()
const emit = defineEmits(['update:modelValue'])
type InsertFnType = (url: string, alt?: string, href?: string) => void
type RichEditorProps = {
  /**值 */
  modelValue: string
  /**内容区域高度 */
  height?: number
  placeholder?: string
  /**文件上传 */
  uploadImg?: (file:File) => Promise<string>
  /**取消配置菜单 */
  excludeMenus?: string[]
  disabled?: boolean
}

const props = withDefaults(defineProps<RichEditorProps>(), {
  placeholder: '请输入内容',
  height: 320,
  excludeMenus: () => ['video']
})

const curVal = ref(props.modelValue)
const isInit = ref(false)

const conRef = ref()
const editor = ref<E>({} as E)
const isFirst = ref(true)

const computedDisabled = computed(() => {
  return props.disabled
})

watch(() => props.modelValue, () => {
  if (curVal.value !== props.modelValue && isInit.value) {
    editor.value.txt.html(props.modelValue)
    curVal.value === props.modelValue
  }
})
watch(() => computedDisabled.value, () => {
  setEdtDisabled(editor.value as E)
})
/**
 * 文本内容变更事件
 */
const handleChange = (newHtml:string) => {
  curVal.value = newHtml
  emit('update:modelValue', newHtml)
  nextTick(() => {
    if (isFirst.value) {
      isFirst.value =false
      return
    }
    try {
      formItem?.validate?.('change')
    } catch (e) {}
  })
}

/**
 * 获取焦点事件
 */
const handleFocus = () => {
}
/**
 * 失去焦点
 */
const handleBlur = () => {
  try {
    formItem?.validate?.('blur')
  } catch (e) {}
}

/**
 * 图片上传
 */
const customUploadImg = async (files: File[], insertFn: InsertFnType) => {
  if (props.uploadImg) {
    for (let file of files) {
      const url = await props.uploadImg(file)
      insertFn(url, file.name)
    }
  }
}

const setEdtDisabled = (edt:E) => {
  if (!isInit.value) return
  if (computedDisabled.value) {
    edt.disable()
  } else {
    edt.enable()
  }
}

const menus = [
  'head',
  'bold',
  'fontSize',
  'fontName',
  'italic',
  'underline',
  'strikeThrough',
  'indent',
  'lineHeight',
  'foreColor',
  'backColor',
  'link',
  'list',
  'todo',
  'justify',
  'quote',
  'image',
  'video',
  'table',
  'code',
  'splitLine',
  'undo',
  'redo',
  'fullScreen'
]

const computedMenus = computed(() => {
  return menus
})
const fullCss = ref('inner-screen')

const handleFullScreen = () => {
  fullCss.value = ''
}

const handleUnFullScreen = () => {
  fullCss.value = 'inner-screen'
}
/**
 * 初始化富文本编辑器配置
 */
const initEdit = (edt:E) => {
  edt.menus.extend('fullScreen', FullScreenMenu)
  edt.config.height = props.height
  edt.config.placeholder = props.placeholder
  edt.config.customUploadImg = customUploadImg
  edt.config.onfocus = handleFocus
  edt.config.onblur = handleBlur
  edt.config.focus = false
  edt.config.showFullScreen = false
  edt.config.onchange = handleChange
  edt.config.menus = computedMenus.value
  const exra:any = edt.config
  exra.onFullScreen = handleFullScreen
  exra.onUnFullScreen= handleUnFullScreen
  edt.create()
  isInit.value = true
  edt.txt.html(props.modelValue)
  setEdtDisabled(edt)
}

onMounted(() => {
  const edt = new E(conRef.value)
  editor.value = edt
  initEdit(edt)
})
onBeforeUnmount(() => {
  editor.value.destroy()
})

const editExpose = {
  isEmpty: () => {
    return !props.modelValue
  },
  getText: () => {
    return editor.value.txt.text()
  },
  dangerouslyInsertHtml: (html:string) => {
    editor.value.cmd.do('insertHTML', html)
  }
}

defineExpose({
  getEditor: () => editExpose
})

</script>
<style lang="scss">
.editor {
  &.inner-screen {
    position: relative;
    z-index: 1;
  }
  .w-e-text-container {
    ul, li {
      list-style: inherit;
    }
  }
}
</style>